package test.test.test;

/*
 *This project covers the basics for a RPG environment. It takes care of the UI and gives two options:
 *Touch control or Digital Control. Both methods utilize A* Pathing to deal with collisions and basic movement
 * The project also takes care of Scene switching and includes transitions between the scenes. It, also, deals
 * with the loading of large TMX maps, if they are loaded repeatedly. Special Layers are also, taken care of. 
 * So far there are layers that animate and layers that the player can go under.    
 * Be Sure to look at the TMX files and see how the properties are used on Layers, Objects, and the Map itself
 */
import java.util.ArrayList;
import java.util.List;
import javax.microedition.khronos.opengles.GL10;

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.BoundCamera;
import org.anddev.andengine.engine.camera.hud.controls.DigitalOnScreenControl;
import org.anddev.andengine.engine.handler.IUpdateHandler;
import org.anddev.andengine.engine.handler.timer.ITimerCallback;
import org.anddev.andengine.engine.handler.timer.TimerHandler;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLayer;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTile;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTiledMap;
import org.anddev.andengine.entity.modifier.IEntityModifier;
import org.anddev.andengine.entity.modifier.PathModifier;
import org.anddev.andengine.entity.modifier.PathModifier.Path;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.scene.background.ColorBackground;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.opengl.texture.Texture;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.opengl.util.GLHelper;
import org.anddev.andengine.ui.activity.BaseGameActivity;
import org.anddev.andengine.util.constants.Constants;
import org.anddev.andengine.util.path.astar.AStarPathFinder;

import android.content.Context;
import android.content.pm.ActivityInfo;
import android.opengl.GLU;

public class Game extends BaseGameActivity implements IOnSceneTouchListener {

	// ===========================================================
	// Constants
	// ===========================================================

	protected static final int CAMERA_WIDTH = 480;
	protected static final int CAMERA_HEIGHT = 320;
	protected static final long[] ANIMATE_DURATION = new long[] { 200, 200, 200 };
	protected static final int TILE_WIDTH = 32;
	protected static final int TILE_HEIGHT = 32;
	protected static final float TILE_ANIMATION_SPEED = 0.5f;
	// Controls the speed the character moves for touch events
	protected static final float TOUCH_SPEED = (float) 0.25;
	protected static final float DIGITAL_SPEED = 0.15f;
	// ===========================================================
	// Fields
	// ===========================================================

	//Engine Fields
	protected static Scene mScene;
	protected static BoundCamera mBoundChaseCamera;

	//Texture Fields
	private Texture mTexturePlayer;
	protected static TiledTextureRegion mPlayerTextureRegion;
	protected static Texture mOnScreenControlTexture;
	protected static TextureRegion mOnScreenControlBaseTextureRegion;
	protected static   TextureRegion mOnScreenControlKnobTextureRegion;
	private Texture FadeTexture;
	private TextureRegion FadeTextureRegion;

	//Sprite Control/UI/Pathing Fields
	protected static DigitalOnScreenControl mDigitalOnScreenControl;
	protected static AnimatedSprite player;
	protected static int playerSpawnDirection;
	protected static org.anddev.andengine.util.path.Path A_path;
	protected static AStarPathFinder<TMXLayer> finder;
	protected static float[] playerFootCordinates;
	protected static Path mCurrentPath;
	protected static boolean isWalking;
	protected static int mWaypointIndex;
	protected static PathModifier mMoveModifier;
	protected static IEntityModifier mPathTemp;

	//TMX Fields
	protected static TMXLoader tmxLoader;
	protected static TMXTiledMap mTMXTiledMap;
	protected static TMXTiledMap mLargeTMXMap;
	protected static TMXLayer TMXMapLayer;
	protected static TMXLayer mTopLayer;
	protected static TMXLayer mAnimateLayer;
	protected static TMXTile playerLocationTile;

	//Lists
	protected static List<TMXTile> CollideTiles;
	protected static List<TMXTile> ExitTiles;
	protected static ArrayList<Integer> MapNumber;
	protected static List<TMXTile> animatedTiles;
	protected static List<TMXTile> playerSpawnTiles;
	protected static ArrayList<Integer> LinkNumber;
	protected static List<TMXTile> propertyTiles;
	protected static ArrayList<Integer> propertyIndex;

	//Indexes
	protected static int mCurrentMapIndex;
	protected static int mLargeTMXIndex = 1000;
	protected static int mLinkIndex;

	//Initial values; These should be initialized from a separate file that was saved before finish();
	protected static float InitialplayerSpawnX = TILE_WIDTH * 5;
	protected static float InitialplayerSpawnY = TILE_HEIGHT * 5;

	//Used to get object tiles in TMX
	protected static int ObjectX;
	protected static int ObjectY;
	protected static int ObjectWidth;
	protected static int ObjectHeight;

	//Boolean Flags
	protected static boolean EnableBounds = true;
	protected static boolean AssetsAttached;
	protected static boolean MapIsLoading;
	protected static boolean TouchOnce;
	protected static boolean UpdateTiles;

	//Misc.
	protected static Sprite FadeScreen;
	protected static Context mContext;

	// ===========================================================
	// Constructors
	// ===========================================================

	// ===========================================================
	// Getter & Setter
	// ===========================================================

	// ===========================================================
	// Methods for/from SuperClass/Interfaces
	// ===========================================================		

	@Override
	public Engine onLoadEngine() {
		// Initializes the Engine and sets the height and width.
		Game.mBoundChaseCamera = new BoundCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT) {
			//Forces the camera to move in integer steps. Helps prevent artifacts from appearing when scrolling
			@Override
			public void onApplySceneMatrix(GL10 pGL) {
				GLHelper.setProjectionIdentityMatrix(pGL);

				GLU.gluOrtho2D(pGL, (int) this.getMinX(), (int) this.getMaxX(), (int) this.getMaxY(),
						(int) this.getMinY());
			}
		};
		//This is used in the TMXMapUpdater() class in the getTMXMap() Mathod
		mContext = getApplicationContext();
		// Sets the orientation of the screen along with the resolution(Multiple displays will see the same image)
		final EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE,
				new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), Game.mBoundChaseCamera);
		// Sets the touch interactions to get processed during the update thread??
		engineOptions.getTouchOptions().setRunOnUpdateThread(true);
		//Forces the screen to go into landscape. Prevents the app from crashing when the screen is being rotated
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
		// Initializes the Engine
		Engine engine = new Engine(engineOptions);
		// Returns the Engine
		return engine;
	}

	//***********************************************************************************************************************

	@Override
	public void onLoadResources() {
		TextureRegionFactory.setAssetBasePath("gfx/");

		// Control texture
		Game.mOnScreenControlTexture = new Texture(256, 128, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		Game.mOnScreenControlBaseTextureRegion = TextureRegionFactory.createFromAsset(Game.mOnScreenControlTexture,
				this, "onscreen_control_base.png", 0, 0);
		Game.mOnScreenControlKnobTextureRegion = TextureRegionFactory.createFromAsset(Game.mOnScreenControlTexture,
				this, "onscreen_control_knob.png", 128, 0);

		// Player sprite texture
		this.mTexturePlayer = new Texture(128, 128, TextureOptions.DEFAULT);
		Game.mPlayerTextureRegion = TextureRegionFactory.createTiledFromAsset(this.mTexturePlayer, this, "hero.png", 0,
				0, 3, 4);

		this.FadeTexture = new Texture(1024, 1024, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		this.FadeTextureRegion = TextureRegionFactory.createFromAsset(this.FadeTexture, getApplicationContext(),
				"FadeBackground.png", 0, 0);
		this.mEngine.getTextureManager().loadTextures(this.mTexturePlayer, Game.mOnScreenControlTexture,
				this.FadeTexture);
	}

	//***********************************************************************************************************************

	@Override
	public Scene onLoadScene() {
		//Logs the FPS in logCat
		this.mEngine.registerUpdateHandler(new FPSLogger());

		//Initializes the scene
		mScene = new Scene();

		//Sets the background to black. Parameters control red, blue, and green (f means the digit is a fraction) 
		mScene.setBackground(new ColorBackground(0f, 0f, 0f));

		//Initializes the TMXLoader
		tmxLoader = new TMXLoader(this, this.mEngine.getTextureManager(), TextureOptions.NEAREST, null);

		FadeScreen = new Sprite(0, 0, FadeTextureRegion);

		//Initial load. In real game the current map index would be saved right before exiting and that index would be passed into this method
		TMXMapUpdater.loadAndAttachAssets(0);

		mScene.registerUpdateHandler(new IUpdateHandler() {

			@Override
			public void reset() {
			}

			@Override
			public void onUpdate(final float pSecondsElapsed) {

				//Allows the tiles to get the player location as soon as possible
				if (UpdateTiles) {

					// Get the scene-coordinates of the tile center. 
					playerFootCordinates = player.convertLocalToSceneCoordinates(16, 16);

					//Get the tile where the center of the current tile is.							 
					playerLocationTile = TMXMapLayer.getTMXTileAt(playerFootCordinates[Constants.VERTEX_INDEX_X],
							playerFootCordinates[Constants.VERTEX_INDEX_Y]);
				}

				//If the TMX map is loading then the scene updates will freeze
				if (!MapIsLoading) {

					//Gets the index of the current map
					mCurrentMapIndex = Integer.parseInt(mTMXTiledMap.getTMXTiledMapProperties().get(0).getValue());

					//This updates the TMX map when the sprite exits or enters the scene					 
					TMXMapUpdater.updateTMXMap();
				}
			}
		});

		//This deals with tile animation 
		mScene.registerUpdateHandler(new TimerHandler(TILE_ANIMATION_SPEED, true, new ITimerCallback() {

			@Override
			public void onTimePassed(final TimerHandler pTimerHandler) {

				if (!MapIsLoading) {

					//Do the random property
					TMXMapUpdater.doProperty1(playerLocationTile);

					TMXMapUpdater.doTileAnimations();

				}
			}
		}));

		//If the options have been set to enable Touch then allow the scene to accept touch events
		if (Options.TouchEnabled) {
			mScene.setOnSceneTouchListener(this);
		}

		return mScene;
	}


	@Override
	public void onLoadComplete() {

	}


	@Override
	public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
		//The constraints on the TouchEvents are there to prevent errors that occur when the screen is touched while loading
		//or if the scene is touched outside of the TMXMap
		if (!MapIsLoading) {
			if (pSceneTouchEvent.isActionDown() && pSceneTouchEvent.getX() < TMXMapLayer.getWidth()
					&& pSceneTouchEvent.getY() < TMXMapLayer.getHeight() && pSceneTouchEvent.getX() > 0
					&& pSceneTouchEvent.getY() > 0 && TouchOnce) {

				//Walks to the touched area
				UI.walkTo(pSceneTouchEvent.getX(), pSceneTouchEvent.getY(), pScene);

				//This is set to true in the GeneralUI
				TouchOnce = false;

				return true;
			}
		}
		return false;
	}

	
	/*@Override
	protected void onPause() {		
		super.onPause();
		//You dont have to have this but there were some errors when going to the menu and back so I figured I'd work on an ingame menu later
		finish();
	}*/

	
	
	// ===========================================================
	// Methods
	// ===========================================================



	// ===========================================================
	// Inner and Anonymous Classes
	// ===========================================================

}